package com.pzhuweb.sgblog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pzhuweb.sgblog.domain.dto.MenuDto;
import com.pzhuweb.sgblog.domain.entity.Menu;
import com.pzhuweb.sgblog.domain.enums.AppHttpCodeEnum;
import com.pzhuweb.sgblog.domain.utils.BeanCopyUtils;
import com.pzhuweb.sgblog.domain.utils.ResponseResult;
import com.pzhuweb.sgblog.domain.utils.SystemConstants;
import com.pzhuweb.sgblog.domain.vo.AdminMenuVo;
import com.pzhuweb.sgblog.domain.vo.MenuDetailsVo;
import com.pzhuweb.sgblog.domain.vo.MenuListVo;
import com.pzhuweb.sgblog.domain.vo.MenuTreeVo;
import com.pzhuweb.sgblog.exception.SystemException;
import com.pzhuweb.sgblog.mapper.MenuMapper;
import com.pzhuweb.sgblog.mapper.SystemMenuMapper;
import com.pzhuweb.sgblog.service.SystemMenuService;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import reactor.util.annotation.Nullable;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;

/**
 * @author 鄧浩奇
 * @classname SystemMenuServiceImpl
 * @description
 * @since 2023/8/23 13:51
 **/
@Service
public class SystemMenuServiceImpl extends ServiceImpl<SystemMenuMapper, Menu> implements SystemMenuService {

    @Resource
    private MenuMapper menuMapper;

    @Override
    public ResponseResult<?> treeSelect() {
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Menu::getId, Menu::getParentId, Menu::getMenuName);
        List<Menu> list = list(wrapper);
        List<AdminMenuVo> menuVos = menuTreeHandel(list);
        return ResponseResult.okResult(menuVos);
    }

    @Override
    public ResponseResult<?> roleMenuTreeSelect(Long id) {
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(Menu::getId, Menu::getParentId, Menu::getMenuName);
        List<Menu> list = list(wrapper);
        List<AdminMenuVo> menuVoList = menuTreeHandel(list);
        // 根据角色id查询关联的查单权限id
        List<Long> checkedKeys = menuMapper.selectMenuIdsByUserId(id);
        // 封装
        MenuTreeVo menusTree = new MenuTreeVo(menuVoList, checkedKeys);
        return ResponseResult.okResult(menusTree);
    }

    @Override
    public ResponseResult<?> getMenuList(String menuName, String status) {
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.hasText(menuName), Menu::getMenuName, menuName)
                .eq(StringUtils.hasText(status), Menu::getStatus, status);
        wrapper.orderByAsc(Menu::getParentId).orderByAsc(Menu::getOrderNum);
        List<Menu> list = list(wrapper);
        List<MenuListVo> menuVos = BeanCopyUtils.copyBeanList(list, MenuListVo.class);
        return ResponseResult.okResult(menuVos);
    }

    @Override
    public ResponseResult<?> addMenu(Menu menu) {
        if (!StringUtils.hasText(menu.getMenuName())) {
            throw new SystemException(AppHttpCodeEnum.MENU_NAME_ISNULL);
        }
        if (!StringUtils.hasText(menu.getOrderNum().toString())) {
            throw new SystemException(AppHttpCodeEnum.ORDER_NUM_ISNULL);
        }
        // 菜单和目录要对路由地址判空
        if (menu.getMenuType().equals(SystemConstants.IS_MENU) || menu.getMenuType().equals(SystemConstants.IS_DIRECTORY)) {
            if (!StringUtils.hasText(menu.getPath())) {
                throw new SystemException(AppHttpCodeEnum.PATH_IS_NULL);
            }
        }
        Menu menus = BeanCopyUtils.copyBean(menu, Menu.class);
        save(menus);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult<?> getMenuDetails(Long menuId) {
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menu::getId, menuId)
                .select(Menu::getId,
                        Menu::getIcon,
                        Menu::getMenuName,
                        Menu::getMenuType,
                        Menu::getOrderNum,
                        Menu::getParentId,
                        Menu::getPath,
                        Menu::getRemark,
                        Menu::getVisible);
        Menu menu = getOne(wrapper);
        MenuDetailsVo menuDetailsVo = BeanCopyUtils.copyBean(menu, MenuDetailsVo.class);
        return ResponseResult.okResult(menuDetailsVo);
    }

    @Override
    public ResponseResult<?> updateMenu(MenuDto menuDto) {
        if (!fieldNonNull(menuDto.getMenuName(), menuDto.getOrderNum(), menuDto.getMenuType(), menuDto.getPath())) {
            throw new SystemException(AppHttpCodeEnum.FIELD_EXIST_NULL);
        }
        if (menuDto.getParentId().equals(menuDto.getId())) {
            return ResponseResult.errorResult(500,"上级菜单不能选择自己");
        }
        LambdaUpdateWrapper<Menu> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Menu::getId,menuDto.getId())
                .set(Menu::getMenuName,menuDto.getMenuName())
                .set(Menu::getMenuType,menuDto.getMenuType())
                .set(Menu::getOrderNum,menuDto.getOrderNum())
                .set(Menu::getParentId,menuDto.getParentId())
                .set(Menu::getStatus,menuDto.getStatus())
                .set(Menu::getIcon,menuDto.getIcon())
                .set(Menu::getPath,menuDto.getPath())
                .set(Menu::getPerms,menuDto.getPerms())
                .set(Menu::getComponent,menuDto.getComponent())
                .set(Menu::getVisible,menuDto.getVisible());
        update(updateWrapper);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult<?> deleteMenuById(Long menuId) {
        Menu menu = getById(menuId);
        if (Objects.isNull(menu)) {
            throw new SystemException(AppHttpCodeEnum.SYSTEM_ERROR);
        }
        // 查询是否有子菜单,根据ParentId查询list集合，集合为空说明没有子菜单
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menu::getParentId,menu.getId());
        List<Menu> list = list(wrapper);
        if (!list.isEmpty()) {
            return ResponseResult.errorResult(AppHttpCodeEnum.SUBMENU_EXIST);
        }
        // 没有子菜单，直接删除
        removeById(menu);
        return ResponseResult.okResult();
    }


    private List<AdminMenuVo> getChildren(AdminMenuVo menuVo, List<AdminMenuVo> menuVoList) {
        return menuVoList.stream()
                .filter(m -> m.getParentId().equals(menuVo.getId()))
                .map(m -> m.setChildren(getChildren(m, menuVoList)))
                .toList();
    }

    /*
     * menu树处理
     * */
    private List<AdminMenuVo> menuTreeHandel(List<Menu> list) {
        List<AdminMenuVo> menuVoList = BeanCopyUtils.copyBeanList(list, AdminMenuVo.class);
        // 对label属性赋值
        list.forEach(menu -> menuVoList.stream()
                .filter(menuVo -> Objects.equals(menuVo.getId(), menu.getId()))
                .findFirst()
                .ifPresent(menuVo -> menuVo.setLabel(menu.getMenuName())));

        // 对子菜单进行处理
        return menuVoList.stream()
                .filter(m -> m.getParentId().equals(0L))
                .map(menuVo -> menuVo.setChildren(getChildren(menuVo, menuVoList))).toList();
    }

    private boolean fieldNonNull(String menuName, Integer orderNum, String menuType, @Nullable String path) {
        if (!StringUtils.hasText(menuName)) {
            return false;
        }
        if (!StringUtils.hasText(orderNum.toString())) {
            return false;
        }
        // 菜单和目录要对路由地址判空
        if (menuType.equals(SystemConstants.IS_MENU) || menuType.equals(SystemConstants.IS_DIRECTORY)) {
            return StringUtils.hasText(path);
        }
        return true;
    }


}
